#include "gamewindow.h"
#include "ui_gamewindow.h"
#include <QDateTime>
#include <QString>
#include <QDebug>
#include <QRandomGenerator>
#include <QUrl>

gamewindow::gamewindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::gamewindow)
{
    ui->setupUi(this);
    qDebug()<<"game window show";
    initGameArgs();
}

gamewindow::~gamewindow()
{
    delete ui;
    delete ticker;
    delete gamePainter;
}

void gamewindow::initGameArgs()
{
    gameArgs.rows = 16;
    gameArgs.cols = 22;
    gameArgs.blockWidth = 30;
    gamePainter = new QPainter;
    gameArgs.gameStatus = GAME_STATUS_INIT;
    gameArgs.direction = MOVE_DIRECTION_RIGHT;
    gameArgs.safeDirection = MOVE_DIRECTION_RIGHT;
    gameArgs.tickerMs = 10;
    gameArgs.speed=GAME_SPEED_SLOW;
    gameArgs.tickerCount = 0;
    gameArgs.score = 0;

    genInitSnakeNode();

    ticker = new QTimer(this);
    connect(ticker, SIGNAL(timeout()), this, SLOT(hanldeTickerTimerout()));
    ticker->start(gameArgs.tickerMs);
    connect(this, SIGNAL(genScoreNodeSig()), this, SLOT(handleGenScoreNode()));
    connect(&gamedia, &gamedia::btnOk, this, &gamewindow::handleDialogOk);
    connect(this, SIGNAL(genGameFailSig()), this, SLOT(handleGameFail()));
    connect(this, SIGNAL(genEatSig()), this, SLOT(handleGameEat()));
    emit genScoreNodeSig();
    initSound();
    initFailSound();
    initEatSound();

}

void gamewindow::initSound()
{
    soundList.addMedia(QUrl("qrc:/wav/bg.mp3"));
//    soundList.addMedia(QUrl("qrc:/wav/bg.mp3"));
    soundList.setPlaybackMode(QMediaPlaylist::Loop);
    soundList.setCurrentIndex(0);
    gameSound.setPlaylist(&soundList);
    gameSound.setVolume(10);
    gameSound.play();

    connect(&gameSound, &QMediaPlayer::mediaStatusChanged,this,&gamewindow::handleBgSoundStatus);
}

void gamewindow::initFailSound()
{
    soundFailList.addMedia(QUrl("qrc:/wav/fail.mp3"));
    soundFailList.setPlaybackMode(QMediaPlaylist::CurrentItemOnce);
    gameFailSound.setPlaylist(&soundFailList);
}

void gamewindow::initEatSound()
{
    soundEatList.addMedia(QUrl("qrc:/wav/eat.mp3"));
    soundEatList.setPlaybackMode(QMediaPlaylist::CurrentItemOnce);
    gameEatSound.setPlaylist(&soundEatList);
}

void gamewindow::printMap()
{
    gamePainter->begin(this);
    gamePainter->setPen(QPen(Qt::white, 1, Qt::SolidLine));//设置画笔形式
    gamePainter->setBrush(QBrush(Qt::lightGray, Qt::SolidPattern));//设置画刷形式

    for (int row = 1; row <= gameArgs.rows ; row++) {
        for (int col = 1; col <= gameArgs.cols; col++) {
            int x1 = col * gameArgs.blockWidth + (col - 1) * 4;
            int y1 = row * gameArgs.blockWidth + (row - 1) * 4;
//            qDebug()<<"paint: snake node at "<<x1<<","<<y1;
            gamePainter->drawRoundRect(x1, y1, gameArgs.blockWidth, gameArgs.blockWidth, 20, 20);
        }
    }
    gamePainter->end();
}

void gamewindow::printMoveSnake()
{
    gamePainter->begin(this);
    gamePainter->setPen(QPen(Qt::white, 1, Qt::SolidLine));//设置画笔形式
    gamePainter->setBrush(QBrush(Qt::red, Qt::SolidPattern));//设置画刷形式

    snakeNode* node = gameArgs.mySnake->head;

    while (node != nullptr) {
        int x1 = node->x;
        int y1 = node->y;
//        qDebug()<<"paint: snake node at "<<x1<<","<<y1;
        gamePainter->drawRoundRect(x1, y1, gameArgs.blockWidth, gameArgs.blockWidth, 20, 20);

        node = node->next;
    }
    gamePainter->end();
}

void gamewindow::printScoreNode()
{
    gamePainter->begin(this);
    gamePainter->setPen(QPen(Qt::white, 1, Qt::SolidLine));//设置画笔形式
    gamePainter->setBrush(QBrush(Qt::blue, Qt::SolidPattern));//设置画刷形式

    snakeNode* node = gameArgs.scoreNode;
    int x1 = node->x;
    int y1 = node->y;
//    qDebug()<<"paint: score node at "<<x1<<","<<y1;
    gamePainter->drawRoundRect(x1, y1, gameArgs.blockWidth, gameArgs.blockWidth, 20, 20);
    gamePainter->end();
}

void gamewindow::genInitSnakeNode()
{
    snake* s = new snake;
    for (int row = 6; row <= 6 ; row++) {
        for (int col = 10; col <= 12; col++) {
            int x1 = col * gameArgs.blockWidth + (col - 1) * 4;
            int y1 = row * gameArgs.blockWidth + (row - 1) * 4;
//            qDebug()<<"add snake node at "<<x1<<","<<y1;
            snakeNode* newNode = new snakeNode(x1, y1, row, col);
            s->addNode(newNode);
        }
    }
    gameArgs.mySnake = s;
}

void gamewindow::genMoveSnakeNode()
{
    int curDirection = gameArgs.safeDirection;

    snakeNode* t = gameArgs.mySnake->tail;
    int curRow = t->row;
    int curCol = t->col;

    // 避免快速按键导致可以反向移动的情况
    if(curDirection == MOVE_DIRECTION_UP && gameArgs.direction == MOVE_DIRECTION_DOWN) {
        gameArgs.direction = MOVE_DIRECTION_UP;
    } else if(curDirection == MOVE_DIRECTION_DOWN && gameArgs.direction == MOVE_DIRECTION_UP) {
        gameArgs.direction = MOVE_DIRECTION_DOWN;
    } else if(curDirection == MOVE_DIRECTION_RIGHT && gameArgs.direction == MOVE_DIRECTION_LEFT) {
        gameArgs.direction = MOVE_DIRECTION_RIGHT;
    } else if(curDirection == MOVE_DIRECTION_LEFT && gameArgs.direction == MOVE_DIRECTION_RIGHT) {
        gameArgs.direction = MOVE_DIRECTION_LEFT;
    } else {
        gameArgs.safeDirection = gameArgs.direction;
        curDirection = gameArgs.safeDirection;
    }

    switch (curDirection) {
        case MOVE_DIRECTION_RIGHT: {
            curCol += 1;
        }break;
        case MOVE_DIRECTION_LEFT: {
            curCol -= 1;
        }break;
        case MOVE_DIRECTION_UP: {
            curRow -= 1;
        }break;
        case MOVE_DIRECTION_DOWN: {
            curRow += 1;
        }break;
    }
    int x1 = curCol * gameArgs.blockWidth + (curCol - 1) * 4;
    int y1 = curRow * gameArgs.blockWidth + (curRow - 1) * 4;
    snakeNode* newTail = new snakeNode(x1, y1, curRow, curCol);

    if(judgeGameFail(curRow, curCol)) {
        gameArgs.gameStatus = GAME_STATUS_FINISH;
        gamedia.show();
        emit genGameFailSig();
        return;
    }

    if(judgeEatScore(curRow, curCol, gameArgs.scoreNode)) {
        qDebug()<<"eat score";
        gameArgs.mySnake->addNode(newTail);
        emit genScoreNodeSig();
        gameArgs.score++;
        emit genEatSig();
        emit genScoreSig(gameArgs.score);
    }else {
        gameArgs.mySnake->move(newTail);
    }

}

void gamewindow::genScoreNode()
{
    int randomX = QRandomGenerator::global()->bounded(gameArgs.rows) + 1;
    int randomY = QRandomGenerator::global()->bounded(gameArgs.cols) + 1;

//    bool ok = false;

    int x1 = randomY * gameArgs.blockWidth + (randomY - 1) * 4;
    int y1 = randomX * gameArgs.blockWidth + (randomX - 1) * 4;
    qDebug()<<"gen score node at "<<x1<<","<<y1;
    qDebug()<<"gen score node at "<<randomX<<","<<randomY;
    snakeNode* scoreNode = new snakeNode(x1, y1, randomX, randomY);
    gameArgs.scoreNode = scoreNode;

}

bool gamewindow::judgeEatScore(int row, int col, snakeNode *node)
{
    return row == node->row && col == node->col;
}

bool gamewindow::judgeGameFail(int row, int col)
{
    return row == 0 || col == 0 || row == gameArgs.rows + 1 || col == gameArgs.cols + 1;
}

void gamewindow::paintEvent(QPaintEvent *)
{
//    qDebug()<<"paint event";
    QPainter p(this);
    p.setPen(QColor("black")); //设置画笔记颜色
    p.drawRect(0, 0, width(), height()); //绘制边

    printMap();
    printMoveSnake();
    printScoreNode();

}

void gamewindow::keyPressEvent(QKeyEvent *event)
{
    // 预期的移动方向，如果按键较快导致和当前方向反向，则本次按键效果失效
    int k = event->key();
    switch (k) {
        case Qt::Key_Up: {
            qDebug()<<"press up";
            if(gameArgs.direction != MOVE_DIRECTION_DOWN) {
                gameArgs.direction = MOVE_DIRECTION_UP;
            }
        }break;
        case Qt::Key_Down: {
            qDebug()<<"press down";
            if(gameArgs.direction != MOVE_DIRECTION_UP) {
                gameArgs.direction = MOVE_DIRECTION_DOWN;
            }
        }break;
        case Qt::Key_Left: {
            qDebug()<<"press left";
            if(gameArgs.direction != MOVE_DIRECTION_RIGHT) {
                gameArgs.direction = MOVE_DIRECTION_LEFT;
            }
        }break;
        case Qt::Key_Right: {
            qDebug()<<"press right";
            if(gameArgs.direction != MOVE_DIRECTION_LEFT) {
                gameArgs.direction = MOVE_DIRECTION_RIGHT;
            }
        }break;
        case Qt::Key_Space: {
            qDebug()<<"press space";
            if(gameArgs.gameStatus == GAME_STATUS_RUNNING) {
                gameArgs.gameStatus = GAME_STATUS_PAUSE;
                emit gameStatusSig(GAME_STATUS_PAUSE);
            } else {
                gameArgs.gameStatus = GAME_STATUS_RUNNING;
                emit gameStatusSig(GAME_STATUS_RUNNING);
            }
        }break;
    }
}

void gamewindow::hanldeTickerTimerout()
{

    // 获取当前日期和时间
//    QDateTime currentDateTime = QDateTime::currentDateTime();
    // 将日期和时间格式化为字符串
//    QString dateTimeString = currentDateTime.toString("yyyy-MM-dd hh:mm:ss");
//    qDebug()<<"ticker: "<<dateTimeString;
    gameArgs.tickerCount++;
    if(gameArgs.tickerCount >= gameArgs.speed && gameArgs.gameStatus == GAME_STATUS_RUNNING) {
        genMoveSnakeNode();
        update();
        gameArgs.tickerCount = 0;
        if(gameArgs.score >= 2 && gameArgs.score <= 5) {
            gameArgs.speed = GAME_SPEED_EASY;
        } else if(gameArgs.score >= 6 && gameArgs.score <= 10) {
            gameArgs.speed = GAME_SPEED_NORMAL;
        } else if(gameArgs.score >= 11 && gameArgs.score <= 15) {
            gameArgs.speed = GAME_SPEED_MEDIUM;
        } else if(gameArgs.score >= 16) {
            gameArgs.speed = GAME_SPEED_HARD;
        }
    }

}

void gamewindow::handleGenScoreNode()
{
    genScoreNode();
    update();
}

void gamewindow::handleDialogOk()
{
    qDebug()<<"dialog ok";
    resetGame();
}

void gamewindow::handleGamePause()
{
    gameArgs.gameStatus = GAME_STATUS_PAUSE;
}

void gamewindow::handleGameFail()
{
    gameFailSound.play();
}

void gamewindow::handleGameEat()
{
    gameEatSound.play();
}

void gamewindow::handleBgSoundStatus(QMediaPlayer::MediaStatus status)
{
    if(status == QMediaPlayer::EndOfMedia)
      {
           gameSound.setPosition(0);
           gameSound.play();
      }
}

void gamewindow::setGameStatus(int status)
{
    qDebug()<<"set game status";
    gameArgs.gameStatus = status;
    emit gameStatusSig(status);
}

void gamewindow::resetGame()
{
    gameArgs.direction=MOVE_DIRECTION_RIGHT;
    gameArgs.safeDirection = MOVE_DIRECTION_RIGHT;
    gameArgs.score = 0;
    gameArgs.speed = GAME_SPEED_SLOW;
    gameArgs.mySnake->clear();
    gameArgs.gameStatus = GAME_STATUS_PAUSE;
    genInitSnakeNode();
    emit genScoreNodeSig();
    emit gameStatusSig(gameArgs.gameStatus);
    emit genScoreSig(gameArgs.score);
}
